package demo04;

/*
 *  Timed Waiting状态：线程处于计时等待状态
 *  进入该状态，可以使用Thread.sleep()带参方法，也可以使用object.wait()带参方法，参数都为等待的毫秒值
 *  sleep()方法只能等待时间到后自动唤醒
 *  wait()方法可以通过其他线程，通过同步代码块/同步方法的同一个锁对象使用notify()/notifyAll()方法提前手动唤醒，也可以等待其自动唤醒
 *  wait()方法的线程在被其他线程唤醒后，会先进入锁阻塞状态，等待其他线程锁释放，马上进入运行状态并执行wait之后的代码
 *  两种方法都会抛出InterruptedException中断异常，需要捕获处理
 */
public class Demo02TimedWaiting {
    public static void main(String[] args) {
        Object object = new Object(); // 锁对象

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    try {
                        System.out.println("线程1使用sleep方法进入休眠zzz，5s自动唤醒...");
                        Thread.sleep(5000); // sleep只能自动在等待后自动唤醒
                        System.out.println("线程1自动唤醒...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println("线程1使用wait方法进入休眠zzz，5s自动唤醒...");
                        object.wait(5000); // wait可以由别的线程通过同一把锁对象提前唤醒，也可以自动唤醒
                        System.out.println("线程1唤醒...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try { // 线程2先进入计时等待0.01s，防止抢跑
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object) {
                    try {
                        System.out.println("线程2在3s后手动唤醒线程1...");
                        Thread.sleep(3000);
                        object.notify(); // 线程2唤醒了线程1，此时线程2还在运行，待运行结束后线程1会马上运行wait后的语句
                        System.out.println("线程2唤醒了线程1...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}
